package config

import (
	"errors"
	"net"
	"sync"
	"time"

	"http_server/src/common_util"
)

var ConnPoolMap = map[string]*ConnPool{}

// init 初始化连接池
func init() {
	for _, v := range ServerList {
		connPool, err := NewConnPool(v, 100, 300*time.Second, 10*time.Second, 10*time.Second)
		if err != nil {
			common_util.ErrorLogger.Printf("创建服务 %s 的连接池失败：%v", v, err)
			continue
		}
		ConnPoolMap[v] = connPool
		common_util.InfoLogger.Printf("创建并初始化服务 %s 的连接池成功", v)
	}
}

// ConnPool TCP连接池
type ConnPool struct {
	address           string             // 服务地址
	pool              chan *Conn         // 连接池
	connMap           map[*Conn]struct{} // 用于存储所有连接
	maxConn           int                // 最大连接数
	coreConnCount     int                // 核心连接数
	idleTimeout       time.Duration      // 空闲连接超时时间
	keepAliveInterval time.Duration      // 核心连接保活间隔
	mu                sync.Mutex         // 锁
	closeChan         chan struct{}      // 关闭信号
	cond              *sync.Cond         // 条件变量，用于等待连接
}

type Conn struct {
	net.Conn
	idleTime time.Time // 空闲时间
	userFlag int       // 是否被获取使用
}

// NewConnPool 创建某个 TCP Server 的连接池
func NewConnPool(address string, maxConn int, idleTimeout time.Duration, keepAliveInterval time.Duration, checkInterval time.Duration) (*ConnPool, error) {
	if maxConn <= 0 {
		return nil, errors.New("最大连接数不能小于等于0")
	}

	pool := &ConnPool{
		address:           address,
		pool:              make(chan *Conn, maxConn),
		connMap:           make(map[*Conn]struct{}),
		maxConn:           maxConn,
		coreConnCount:     maxConn / 2, // 核心连接数为最大连接数的一半
		idleTimeout:       idleTimeout,
		keepAliveInterval: keepAliveInterval,
		closeChan:         make(chan struct{}),
	}
	// 关闭空闲连接
	go pool.checkIdleConn(checkInterval)
	// 核心连接的 保活
	// go pool.keepAliveConn()
	return pool, nil
}

// GetConn 从连接池中获取一个连接
func (p *ConnPool) GetConn() (*Conn, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	// 检查连接池中是否有空闲连接
	for conn := range p.connMap {
		// 该连接正在被使用，则跳过
		if conn.userFlag == 1 {
			continue
		}
		// 当前时间减去该连接的创建时间， 如果小于 线程池允许的空闲时间，则该连接允许存活，否则，关闭该连接
		if time.Now().Sub(conn.idleTime) < p.idleTimeout {
			delete(p.connMap, conn) // 从 map 中移除
			p.pool <- conn          // 放回通道
			conn.idleTime = time.Now()
			return conn, nil
		} else {
			err := conn.Conn.Close()
			if err != nil {
				common_util.ErrorLogger.Printf("关闭空闲超时的连接出现异常：%v", err)
			}
			delete(p.connMap, conn)
			common_util.InfoLogger.Printf("关闭空闲超时的连接：%v", conn.Conn.RemoteAddr())
		}
	}

	// 如果连接数未达到最大值，并且当前连接池内无可用的连接，则创建新的连接
	if len(p.connMap) < p.maxConn {
		conn, err := p.createConn()
		if err != nil {
			return nil, err
		}
		conn.idleTime = time.Now()
		conn.userFlag = 1
		p.pool <- conn
		p.connMap[conn] = struct{}{}
		return conn, nil
	}

	// 如果连接数已达到最大值，但没有可用连接，等待
	select {
	case conn := <-p.pool:
		// 设置使用时间和使用标识
		conn.idleTime = time.Now()
		conn.userFlag = 1
		return conn, nil

	case <-time.After(p.idleTimeout):
		return nil, errors.New("等待【" + p.address + "】连接池内的连接超时")

	case <-p.closeChan:
		return nil, errors.New(p.address + "连接池已被关闭")
	}
}

// ReleaseConn 将连接归还到连接池
func (p *ConnPool) ReleaseConn(conn *Conn) error {
	p.mu.Lock()
	defer p.mu.Unlock()

	select {
	case <-p.closeChan:
		err := conn.Conn.Close()
		if err != nil {
			return err
		}
		common_util.InfoLogger.Printf("关闭连接：%v", conn.Conn.RemoteAddr())
		delete(p.connMap, conn)
		return nil

	default:
		// 如果连接数超过核心连接数，关闭该连接
		if len(p.connMap) >= p.maxConn {
			err := conn.Conn.Close()
			if err != nil {
				return err
			}
			common_util.InfoLogger.Printf("关闭多余连接：%v", conn.Conn.RemoteAddr())
			delete(p.connMap, conn)
			return nil
		}

		// 否则，将连接放回连接池
		conn.idleTime = time.Now()
		conn.userFlag = 0
		p.pool <- conn
		p.connMap[conn] = struct{}{}
		return nil
	}
}

// createConn 创建一个新的 TCP 连接
func (p *ConnPool) createConn() (*Conn, error) {
	conn, err := net.Dial("tcp", p.address)
	if err != nil {
		return nil, err
	}
	return &Conn{Conn: conn, idleTime: time.Now()}, nil
}

// Close 关闭连接池，释放所有连接
func (p *ConnPool) Close() {

	p.mu.Lock()
	defer p.mu.Unlock()

	close(p.closeChan)

	// 关闭所有连接
	for conn := range p.connMap {
		err := conn.Conn.Close()
		if err != nil {
			common_util.ErrorLogger.Printf("关闭连接失败：%v", err)
		}
		delete(p.connMap, conn)
	}

	// 关闭通道
	close(p.pool)
	common_util.InfoLogger.Printf("关闭连接池：%s", p.address)

}

// checkIdleConn 定期检查空闲连接并关闭超时的连接
func (p *ConnPool) checkIdleConn(checkInterval time.Duration) {
	ticker := time.NewTicker(checkInterval)
	defer ticker.Stop()

	for {
		common_util.InfoLogger.Printf("检查并关闭空闲的连接")
		select {
		case <-ticker.C:
			p.mu.Lock()
			now := time.Now()

			var activeConn []*Conn
			for conn := range p.connMap {
				// 该连接有人正在使用，或者还未超时
				if conn.userFlag == 1 || now.Sub(conn.idleTime) < p.idleTimeout {
					activeConn = append(activeConn, conn)
				} else {
					err := conn.Conn.Close()
					if err != nil {
						common_util.ErrorLogger.Printf("关闭空闲超时连接出现异常：%v", err)
					}
				}
			}

			// 清空旧的连接集合
			p.connMap = make(map[*Conn]struct{})

			// 将未超时的连接重新放回连接池
			for _, conn := range activeConn {
				p.connMap[conn] = struct{}{}
				p.pool <- conn
			}

			p.mu.Unlock()

		case <-p.closeChan:
			return
		}
	}
}

// keepAliveConn 定期对核心连接进行保活
func (p *ConnPool) keepAliveConn() {
	ticker := time.NewTicker(p.keepAliveInterval)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			p.mu.Lock()
			now := time.Now()
			common_util.InfoLogger.Printf("执行核心连接的保活处理")
			for conn := range p.connMap {
				if conn.userFlag == 1 {
					continue
				}
				if len(p.connMap) <= p.coreConnCount && now.Sub(conn.idleTime) > p.keepAliveInterval/2 {
					// 发送心跳包
					_, err := conn.Conn.Write([]byte("PING"))
					if err != nil {
						err := conn.Conn.Close()
						if err != nil {
							common_util.ErrorLogger.Printf("核心连接保活失败：%v", err)
						}
						delete(p.connMap, conn)
					} else {
						common_util.InfoLogger.Printf("核心连接保活成功：%v", conn.Conn.RemoteAddr())
					}
				}
			}
			p.mu.Unlock()

		case <-p.closeChan:
			return
		}
	}
}
